//
//	HOME AUTOMATION GATEWAY PROJECT
//
//  (c) 2008 mocom software GmbH & Co KG
//	for European Microsoft Innovation Center
//
//  $Author: volker $
//  $Date: 2009-06-12 17:09:34 +0200 (Fr, 12. Jun 2009) $
//  $Revision: 379 $
//
//  Microsoft dotNetMF Project
//  Copyright ©2001,2002,2003,2004 Microsoft Corporation
//  One Microsoft Way, Redmond, Washington 98052-6399 U.S.A.
//  All rights reserved.
//  MICROSOFT CONFIDENTIAL
//
//-----------------------------------------------------------------------------

#include <tinyhal.h>
#include "AT91_GPIO.h"
#include "HAG_XR16l784_GPIO.h"
#include "..\usart_options.h"


#define _COM4	3
#define _COM5	4
#define _COM6	5
#define _COM7	6


//--//

#undef  TRACE_ALWAYS

#define TRACE_ALWAYS               0x00000001

#undef  DEBUG_TRACE
#define DEBUG_TRACE (TRACE_ALWAYS)

#if DEBUG
#define DBG				hal_printf
#define DBGGPIO(f,x)	hal_printf(f ": " #x "=%d\r\n",x)
#else
#define DBGGPIO(f,x)
#define DBG				nul
static void nul(char *fmt, ...)
{
}
#endif

//--//

#if defined(ADS_LINKER_BUG__NOT_ALL_UNUSED_VARIABLES_ARE_REMOVED)
#pragma arm section rodata = "c_Gpio_Attributes_AT91"
#endif

const UINT8 HAG_XR16l784_GPIO_Driver::c_Gpio_Attributes[HAG_XR16l784_GPIO_Driver::c_MaxPins] =
{
    GPIO_ATTRIBUTE_INPUT,	//	0							COM4_CTS
    GPIO_ATTRIBUTE_INPUT,	// 	1							COM7_CTS
	GPIO_ATTRIBUTE_INPUT,	// 	2							COM7_DSR
	GPIO_ATTRIBUTE_INPUT,	// 	3							COM7_DCD
	GPIO_ATTRIBUTE_INPUT,	// 	4							COM7_RI
	0,						// 	5							
	0,						// 	6							
	0,						// 	7							
	
	GPIO_ATTRIBUTE_OUTPUT,	//	8   (register 0)	    	COM4_RTS
    GPIO_ATTRIBUTE_OUTPUT, 	//	9							COM6_DUPLEX
    GPIO_ATTRIBUTE_OUTPUT, 	//  10							COM7_RTS
	GPIO_ATTRIBUTE_OUTPUT,	// 	11							COM7_DTR
	
	
};

#if defined(ADS_LINKER_BUG__NOT_ALL_UNUSED_VARIABLES_ARE_REMOVED)
#pragma arm section rodata
#endif

//--//

#if defined(ADS_LINKER_BUG__NOT_ALL_UNUSED_VARIABLES_ARE_REMOVED)
#pragma arm section zidata = "gHAG_XR16l784_GPIO_Driver_GPIO_Driver"
#endif

HAG_XR16l784_GPIO_Driver gHAG_XR16l784_GPIO_Driver;

#if defined(ADS_LINKER_BUG__NOT_ALL_UNUSED_VARIABLES_ARE_REMOVED)
#pragma arm section zidata
#endif

//--//
BOOL HAG_XR16l784_GPIO_Driver::Initialize()
{
	for (int i=0;i<c_MaxPins;i++) 
	{
		gHAG_XR16l784_GPIO_Driver.m_IOMap_Old[i] = 
		gHAG_XR16l784_GPIO_Driver.m_IOMap[i] = 0;
	}
	
	return TRUE;
}

//--//

BOOL HAG_XR16l784_GPIO_Driver::Uninitialize()
{
    return TRUE;
}

//--//

UINT32 HAG_XR16l784_GPIO_Driver::Attributes( GPIO_PIN Pin )
{
	DBGGPIO("Attributes",Pin);

	if(Pin < c_MaxPins)
    {
        return c_Gpio_Attributes[Pin];
    }
    return GPIO_ATTRIBUTE_NONE;
}

//--//

void HAG_XR16l784_GPIO_Driver::DisablePin( GPIO_PIN pin, GPIO_RESISTOR resistorState, UINT32 dir_out, GPIO_ALT_MODE function )
{
	gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[pin].code = NULL;
	gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[pin].data = NULL;
	gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[pin].mode = 0;
	switch (pin) {
		case COM4_CTS-c_FirstIo:
			CPU_USART_SetOption(_COM4,USART_OPT_DEL_FROM_RQMASK,USART_OPT_CTS);
			break;
		case COM7_CTS-c_FirstIo:
			CPU_USART_SetOption(_COM7,USART_OPT_DEL_FROM_RQMASK,USART_OPT_CTS);
			break;
		case COM7_DSR-c_FirstIo:
			CPU_USART_SetOption(_COM7,USART_OPT_DEL_FROM_RQMASK,USART_OPT_DSR);
			break;
		case COM7_DCD-c_FirstIo:
			CPU_USART_SetOption(_COM7,USART_OPT_DEL_FROM_RQMASK,USART_OPT_DCD);
			break;
		case COM7_RI-c_FirstIo:
			CPU_USART_SetOption(_COM7,USART_OPT_DEL_FROM_RQMASK,USART_OPT_RI);
		default:
			break;
	}		
}

//--//

void HAG_XR16l784_GPIO_Driver::EnableOutputPin( GPIO_PIN pin, BOOL initialState )
{
	SetPinState(pin,initialState);
}

//--//

BOOL HAG_XR16l784_GPIO_Driver::EnableInputPin( GPIO_PIN pin, BOOL GlitchFilterEnable, GPIO_INTERRUPT_SERVICE_ROUTINE ISR, void* pinIsrParam, GPIO_INT_EDGE intEdge, GPIO_RESISTOR resistorState )
{
    if(ISR)
    {
		// attach isr
		gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[pin].code = ISR;
		gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[pin].data = pinIsrParam;
		gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[pin].mode = intEdge;
		// now, is it supported?
		switch (pin) {
			case COM4_CTS-c_FirstIo:
				CPU_USART_SetOption(_COM4,USART_OPT_ADD_TO_RQMASK,USART_OPT_CTS);
				break;
			case COM7_CTS-c_FirstIo:
				CPU_USART_SetOption(_COM7,USART_OPT_ADD_TO_RQMASK,USART_OPT_CTS);
				break;
			case COM7_DSR-c_FirstIo:
				CPU_USART_SetOption(_COM7,USART_OPT_ADD_TO_RQMASK,USART_OPT_DSR);
				break;
			case COM7_DCD-c_FirstIo:
				CPU_USART_SetOption(_COM7,USART_OPT_ADD_TO_RQMASK,USART_OPT_DCD);
				break;
			case COM7_RI-c_FirstIo:
				CPU_USART_SetOption(_COM7,USART_OPT_ADD_TO_RQMASK,USART_OPT_RI);
				break;
			default:
				return FALSE;
		}		
		CPU_USART_SetOption(_COM4,USART_OPT_SET_MODEM_CALLBACK,(UINT32)UARTCallback);
    }

    return TRUE;
}


BOOL HAG_XR16l784_GPIO_Driver::GetPinState( GPIO_PIN pin )
{
	DBGGPIO("GetPinState",pin);
	UINT32 val = 0;

    ASSERT(pin < c_MaxPins);
	
	switch (pin) {
		case COM4_RTS-c_FirstIo:
			CPU_USART_GetOption(_COM4,USART_OPT_RTS,&val);
			break;
			
		case COM4_CTS-c_FirstIo:
			CPU_USART_GetOption(_COM4,USART_OPT_CTS,&val);
			break;
		
		case COM6_DUPLEX-c_FirstIo:
			// COM6_DUPLEX: 1=FULL, ==HALF
			CPU_USART_GetOption(_COM6,USART_OPT_DUPLEX,&val);
			val = (val == USART_OPT_FULLDUPLEX); 
			break;
			
		case COM7_DTR-c_FirstIo:
			CPU_USART_GetOption(_COM7,USART_OPT_DTR,&val);
			break;

		case COM7_RTS-c_FirstIo:
			CPU_USART_GetOption(_COM7,USART_OPT_RTS,&val);
			break;

		case COM7_CTS-c_FirstIo:
			CPU_USART_GetOption(_COM7,USART_OPT_CTS,&val);
			break;

		case COM7_DSR-c_FirstIo:
			CPU_USART_GetOption(_COM7,USART_OPT_DSR,&val);
			break;

		case COM7_DCD-c_FirstIo:
			CPU_USART_GetOption(_COM7,USART_OPT_DCD,&val);
			break;

		case COM7_RI-c_FirstIo:
			CPU_USART_GetOption(_COM7,USART_OPT_RI,&val);
			break;

		default:		
			break;
	}
	
	debug_printf("pin=%d val=%ld\r\n",pin,val);
	
	// log it
	gHAG_XR16l784_GPIO_Driver.m_IOMap[pin] = val;

	return val != 0;	
}

//--//

void HAG_XR16l784_GPIO_Driver::SetPinState( GPIO_PIN pin, BOOL pinState )
{
	UINT32 val = (UINT32) pinState;
	
	GLOBAL_LOCK(irq);

	// log it
	gHAG_XR16l784_GPIO_Driver.m_IOMap[pin] = pinState;
	// set it
	switch (pin) {
		case COM4_RTS-c_FirstIo:
			CPU_USART_SetOption(_COM4,USART_OPT_RTS,val);
			break;
		
		case COM6_DUPLEX-c_FirstIo:
			if (pinState) 
				CPU_USART_SetOption(_COM6,USART_OPT_DUPLEX,USART_OPT_FULLDUPLEX);	
			else
				CPU_USART_SetOption(_COM6,USART_OPT_DUPLEX,USART_OPT_HALFDUPLEX);
			break;

		case COM7_RTS-c_FirstIo:
			CPU_USART_SetOption(_COM7,USART_OPT_RTS,val);
			break;

		case COM7_DTR-c_FirstIo:
			CPU_USART_SetOption(_COM7,USART_OPT_DTR,val);
			break;

		default:		
			break;
	}
}

//--//


void HAG_XR16l784_GPIO_Driver::UARTCallback(int com, int pin, bool value, void *param)
{
	
	int io = 0;
	bool trigger;
	
	GLOBAL_LOCK(irq);

	// map usart channel/usart pin to virtual pin
	switch (com) 
	{
		case _COM4:
			if (pin == USART_OPT_CTS) {
				io = COM4_CTS;
				break;
			}
			return;
			
		case _COM7:
			switch (pin) 
			{
				case USART_OPT_CTS:
					io = COM7_CTS;
					break;
				case USART_OPT_DSR:
					io = COM7_DSR;
					break;
				case USART_OPT_DCD:
					io = COM7_DCD;
					break;
				case USART_OPT_RI:
					io = COM7_RI;
					break;
				default: 
					return;	
			}
			break;
		default:
			// not interested in all the other pins
			return;
	}
	
	// as we get here if there was an level change ONLY, we 
	// can assume we have a rising or falling edge!
	if (gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[io-c_FirstIo].code) {
		switch (gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[io-c_FirstIo].mode) {
			case GPIO_INT_EDGE_BOTH:
				trigger = true;
				break;
			case GPIO_INT_LEVEL_HIGH:
			case GPIO_INT_EDGE_HIGH:
				trigger = value != 0;
				break;
			case GPIO_INT_LEVEL_LOW:
			case GPIO_INT_EDGE_LOW:
			trigger = value == 0;
				break;
			default:
				trigger = 0;
		}
		if (trigger) {
			gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[io-c_FirstIo].code(io,value,gHAG_XR16l784_GPIO_Driver.m_IsrCallbacks[io-c_FirstIo].data);
		}
	}
}

//--//

void HAG_XR16l784_GPIO_Driver::SetResistor( GPIO_PIN pin, GPIO_RESISTOR resistorState )
{
}

//--//

BOOL HAG_XR16l784_GPIO_Driver::PinIsBusy( GPIO_PIN pin )
{
	DBGGPIO("PinIsBusy",pin);

    return gHAG_XR16l784_GPIO_Driver.m_PinReservationInfo[pin];
}

//--//

BOOL HAG_XR16l784_GPIO_Driver::ReservePin( GPIO_PIN pin, BOOL fReserve )
{
    GLOBAL_LOCK(irq);

	DBGGPIO("ReservePin",pin);

	if (gHAG_XR16l784_GPIO_Driver.m_PinReservationInfo[pin] && fReserve)
		return FALSE;
	if (!gHAG_XR16l784_GPIO_Driver.m_PinReservationInfo[pin] && !fReserve)
		return FALSE;

	gHAG_XR16l784_GPIO_Driver.m_PinReservationInfo[pin] = fReserve;

    return TRUE;
}

//--//

void HAG_XR16l784_GPIO_Driver::GetPinsMap( UINT8* pins, size_t size )
{
    const UINT8*    src = c_Gpio_Attributes;
    UINT8* dst = pins;
    UINT32 maxpin = c_MaxPins;

    if ( size ==0 ) return;
    while ((size--) && (maxpin --))
    {
        *dst = *src;
        ++dst; ++src;
    }
}


